<template>
	<div
		:class="[prefixCls]"
		v-click-outside="onClickoutside"
		@mouseenter="handleMouseenter"
		@mouseleave="handleMouseleave"
	>
		<div
			:class="relClasses"
			ref="reference"
			@click="handleClick"
			@contextmenu.prevent="handleRightClick"
		>
			<slot></slot>
		</div>
		<transition name="transition-drop">
			<Drop
				:class="dropdownCls"
				v-show="currentVisible"
				:placement="placement"
				ref="drop"
				@mouseenter.native="handleMouseenter"
				@mouseleave.native="handleMouseleave"
				:data-transfer="transfer"
				:transfer="transfer"
				v-transfer-dom
			>
				<slot name="list"></slot>
			</Drop>
		</transition>
	</div>
</template>
<script lang="ts">
	import Drop from "../select/drop.vue";
	import { ClickOutside } from "../../directives/clickoutside";
	import TransferDom from "../../directives/transfer-dom";
	import { oneOf, findComponentUpward } from "../../utils/assist";

	const prefixCls = "ivu-dropdown";
	import Anes from "../base";
	import { Prop, Component, Watch } from "vue-property-decorator";
	import DropItem from "../select/drop.vue";
	@Component({
		name: "Dropdown",
		directives: { ClickOutside, TransferDom },
		components: { Drop }
	})
	export default class Dropdown extends Anes {
		@Prop({
			type: String,
			validator(value) {
				return oneOf(value, ["click", "hover", "custom", "contextMenu"]);
			},
			default: "hover"
		})
		trigger!: string;
		@Prop({
			validator(value) {
				return oneOf(value, [
					"top",
					"top-start",
					"top-end",
					"bottom",
					"bottom-start",
					"bottom-end",
					"left",
					"left-start",
					"left-end",
					"right",
					"right-start",
					"right-end"
				]);
			},
			default: "bottom"
		})
		public placement!: string;

		@Prop({ type: Boolean, default: false }) visible!: boolean;
		@Prop({ type: Boolean, default: false }) stopPropagation!: boolean;
		@Prop() transferClassName!: string;
		//@Prop() stopPropagation: boolean = !this.$IVIEW ? true : this.$IVIEW.capture;
		prefixCls = prefixCls;
		currentVisible = this.visible;
		timeout!: number;
		get transition() {
			return ["bottom-start", "bottom", "bottom-end"].indexOf(this.placement) > -1
				? "slide-up"
				: "fade";
		}
		get dropdownCls() {
			return {
				[prefixCls + "-transfer"]: this.transfer,
				[this.transferClassName]: this.transferClassName
			};
		}
		get relClasses() {
			return [
				`${prefixCls}-rel`,
				{
					[`${prefixCls}-rel-user-select-none`]: this.trigger === "contextMenu"
				}
			];
		}
		get drop() {
			return this.$refs.drop as DropItem;
		}

		@Watch("visible")
		onVisible(val: boolean) {
			this.currentVisible = val;
		}
		@Watch("currentVisible")
		oncurrentVisible(val: boolean) {
			if (val) {
				this.drop?.update();
			} else {
				this.drop?.destroy();
			}
			this.$emit("on-visible-change", val);
		}

		handleClick() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "click") {
				return false;
			}
			this.currentVisible = !this.currentVisible;
		}
		handleRightClick() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "contextMenu") {
				return false;
			}
			this.currentVisible = !this.currentVisible;
		}
		handleMouseenter() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "hover") {
				return false;
			}
			if (this.timeout) clearTimeout(this.timeout);
			this.timeout = setTimeout(() => {
				this.currentVisible = true;
			}, 250);
		}
		handleMouseleave() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "hover") {
				return false;
			}
			if (this.timeout) {
				clearTimeout(this.timeout);
				this.timeout = setTimeout(() => {
					this.currentVisible = false;
				}, 150);
			}
		}
		onClickoutside(e: Event) {
			this.handleClose();
			this.handleRightClose();
			if (this.currentVisible) this.$emit("on-clickoutside", e);
		}
		handleClose() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "click") {
				return false;
			}
			this.currentVisible = false;
		}
		handleRightClose() {
			if (this.trigger === "custom") return false;
			if (this.trigger !== "contextMenu") {
				return false;
			}
			this.currentVisible = false;
		}
		hasParent() {
			return findComponentUpward<Dropdown>(this, "Dropdown");
		}
		mounted() {
			this.$on("on-click", (key: Event) => {
				if (this.stopPropagation) return;
				const $parent = this.hasParent();
				if ($parent) $parent.$emit("on-click", key);
			});
			this.$on("on-hover-click", () => {
				const $parent = this.hasParent();
				if ($parent) {
					this.$nextTick(() => {
						if (this.trigger === "custom") return false;
						this.currentVisible = false;
					});
					$parent.$emit("on-hover-click");
				} else {
					this.$nextTick(() => {
						if (this.trigger === "custom") return false;
						this.currentVisible = false;
					});
				}
			});
			this.$on("on-haschild-click", () => {
				this.$nextTick(() => {
					if (this.trigger === "custom") return false;
					this.currentVisible = true;
				});
				const $parent = this.hasParent();
				if ($parent) $parent.$emit("on-haschild-click");
			});
		}
	}
</script>
 